package com.sxhuayuan.parking.plugin.parking.bluecard;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.sxhuayuan.parking.compenent.Message;
import com.sxhuayuan.parking.compenent.web.RespMessage;
import com.sxhuayuan.parking.config.PayMode;
import com.sxhuayuan.parking.config.PayStatus;
import com.sxhuayuan.parking.config.Platform;
import com.sxhuayuan.parking.dto.CreateMcardChargeOrderDTO;
import com.sxhuayuan.parking.dto.ParkFeeCacheBean;
import com.sxhuayuan.parking.entity.*;
import com.sxhuayuan.parking.exception.MyException;
import com.sxhuayuan.parking.plugin.parking.ParkingPlugin;
import com.sxhuayuan.parking.plugin.parking.bluecard.request.BluecardNotifyParkingFeeOrderSuccess;
import com.sxhuayuan.parking.plugin.parking.bluecard.request.BluecardQueryParkingFeeRequestData;
import com.sxhuayuan.parking.plugin.parking.bluecard.result.BluecardCharge;
import com.sxhuayuan.parking.plugin.parking.bluecard.result.BluecardResult;
import com.sxhuayuan.parking.plugin.parking.bluecard.result.BluecardResultData;
import com.sxhuayuan.parking.plugin.parking.result.*;
import com.sxhuayuan.parking.queue.msg.NotifyParkingLotMsg;
import com.sxhuayuan.parking.service.*;
import com.sxhuayuan.parking.service.impl.pojo.ExitingCar;
import com.sxhuayuan.parking.utils.DateUtils;
import com.sxhuayuan.parking.utils.Md5Utils;
import com.sxhuayuan.parking.utils.SequenceUtils;
import com.sxhuayuan.parking.utils.SettingUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component(BluecardParkingPlugin.ID)
public class BluecardParkingPlugin extends ParkingPlugin {

	public static final String ID = "bluecardParkingPlugin";

	private static final Map<String, String> HEADER = new HashMap<String, String>();
	static {
		HEADER.put("Content-Type", "application/json;charset=utf-8");
	}

	Logger log = LoggerFactory.getLogger(getClass());

	@Autowired
	private ParkingInService inService;
	@Resource(name = "parkChannelServiceImpl")
	private ParkChannelService channelService;
	@Resource(name = "parkingInOutServiceImpl")
	private ParkingInOutService parkingInOutServiceImpl;
	@Autowired
	private ParkingLotService lotService;
	@Autowired
	private OrderService orderService;
	@Autowired
	PluginService pluginService;
	@Autowired
	ExitingCarService exitingCarService;
	@Autowired
	SequenceUtils sequenceUtils;

	@Override
	public String getId() {
		return ID;
	}

	@Override
	public String getName() {
		return "蓝卡云";
	}

	// 支持出入场通知
	@Override
	public boolean isSupportEventPush() {
		return true;
	}

	// 请求算费
	@Override
	public ParkFeeCacheBean saveParkInRecord(String lotSn, String carPlate, String resp) {
		return JSONObject.parseObject(resp, ParkFeeCacheBean.class);
	}

	// 应该是预支付 , 走的是算费请求 传来的lotSn代表我方车厂编号
	@Override
	public QueryParkingFeeResultWrap queryParkingFee(ParkingLot lot, String carPlate) {
		log.debug("调用接口查询停车费: lotSn={}, carPlate={}", lot, carPlate);
		BluecardQueryParkingFeeRequestData data = new BluecardQueryParkingFeeRequestData();
		// 根据车牌查出车辆入场信息
		ParkingIn in = inService.findByCarPlate(lot.getId(), carPlate);
		Assert.notNull(in, "未查到入场信息");
		// 存入第三方车厂编号
		data.setParkNumber(lot.getLotSn());
		data.setPlate(carPlate);
		data.setOrderId(in.getLotRecordId());
		String sign = Md5Utils.md5(lot.getApiKey() + data.getParkNumber());
		// 发送查询费用请求 发送的请求数据 是已经封装好的JSON
		String resp = httpPost(lot, "/bcopenapi/out/getChargebf", JSONObject.toJSONString(data), sign);
		log.debug("预支付: ---- 请求算费结果 = {}", resp);
		if (resp == null) {
			throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
		}
		// 组装订单
		JSONObject httpResp = JSON.parseObject(resp);
		boolean isSuccess = "success".equals(httpResp.getString("status"));
		QueryParkingFeeResultWrap rs = new QueryParkingFeeResultWrap();

		rs.setIsSuccess(isSuccess);
		if (isSuccess) {
			JSONObject respData = httpResp.getJSONObject("datas");
			rs.setCarPlate(respData.getString("plate"));
			// 总计
			rs.setCalcFee(respData.getFloatValue("charge"));
			// 实收=总计-优惠
			Float fee = respData.getFloatValue("payCharge");
			rs.setFee(fee);
			String inTime = respData.getString("inTime");
			rs.setEntertime(inTime);
			rs.setCalcStartTime(inTime);
			String endTime = respData.getString("getTime");
			rs.setCalcEndTime(endTime);
			rs.setExtraMchid(lot.getSn());
			rs.setExtraPluginId(ID);
			// 总停车时长
			rs.setParktimeMinute(respData.getInteger("stopTimeTotal"));
			// 车场订单号 目前填充车厂流水号 orderNo作为车辆入场比那好, 暂时不填写
			rs.setLotOrderNo(respData.getString("outTradeNo"));
			// 暂无计费规则
			// rs.setRules(respData.getString("priceRule"));
			String parkFeeCacheBean = respToParkFeeCacheBeanQueryParkingFee(lot.getSn(), resp);
			Long uniqueId = submitUpdateOriginalInfoTask(lot.getSn(), carPlate, fee, parkFeeCacheBean);
			rs.setUniqueId(uniqueId != null ? String.valueOf(uniqueId) : "");
			// 车厂流水号
			// rs.setNo(respData.getString("outTradeNo"));
			// 车厂时间戳
			rs.setTime(DateUtils.parse(httpResp.getString("timeStamp")));
		} else {
			rs.setMsg(httpResp.getString("errorCode"));
		}
		return rs;
	}

	/**
	 * 因为请求订单的方式不同, 所以数据结果不同, 这区将预支付和 扫码支付通道数据解析分开
	 * 
	 * @param resp
	 * @return
	 */
	private String respToParkFeeCacheBeanQueryParkingFee(String lotSn, String resp) {
		JSONObject datas = JSONObject.parseObject(resp).getJSONObject("datas");
		ParkingLot lot = lotService.findBySn(lotSn);
		String carPlate = datas.getString("plate");
		Date inTime = DateUtils.parse(datas.getString("inTime"));
		String orderId = datas.getString("orderId");
		/** 蓝卡返回的信息无车道信息 所以填null */
		ParkingIn in = inService.enter(lot, carPlate, inTime, null, lot.getFreeMinutes(), orderId, null);
		// 车厂订单编号, 车辆入场时由车厂生成
		String lotOrderSn = datas.getString("outTradeNo");
		Date endTime = DateUtils.parse(datas.getString("getTime"));
		ParkFeeCacheBean bean = new ParkFeeCacheBean();
		bean.setCarPlate(carPlate);
		bean.setEndTime(endTime);
		bean.setLotOrderNo(lotOrderSn);
		bean.setParkPluginId(ID);
		bean.setTotalFee(datas.getFloat("charge"));
		bean.setDiscountFee(datas.getFloat("profitChargeTotal"));
		bean.setUniqueId(in.getUniqueId());
		return JSONObject.toJSONString(bean);
	}

	// 应该是扫码支付出场
	@Override
	public QueryParkingFeeResultWrap queryLeavingCarParkingLotOrder(ParkingLot lot, String exitSn, Member member) {
		QueryParkingFeeResultWrap qf = new QueryParkingFeeResultWrap();
		// 订单不存在
		if (!exitingCarService.hasKey(exitSn)) {
			qf.setIsSuccess(false);
			qf.setMsg("未找到订单");
			return qf;
		}
		// 获取redis中的指定消息
		ExitingCar exit = exitingCarService.get(exitSn);
		// 此订单存在已经超过五分钟
		Date outTime = DateUtils.parse(exit.getOutTime());
		Long out = outTime.getTime();
		Long interval = System.currentTimeMillis() - out;
		if (interval > 5 * 60 * 1000) {
			exitingCarService.remove(exitSn);
			qf.setIsSuccess(false);
			qf.setMsg("订单时间过长");
			return qf;
		}
		// 此订单存在已经超过五分钟
		qf.setCarPlate(exit.getCarPlate());
		qf.setEntertime(exit.getInTime());
		qf.setCalcStartTime(exit.getInTime());
		qf.setCalcEndTime(exit.getOutTime());
		qf.setParktimeMinute(exit.getParkMinutes());
		Float totalCalcFee = SettingUtils.get().setScale(BigDecimal.valueOf((exit.getDiscountFee() + exit.getFee()))).floatValue();
		qf.setCalcFee(totalCalcFee);
		qf.setFee(exit.getFee());
		qf.setLotOrderNo(exit.getLotOrderNo());
		qf.setExtraMchid(lot.getSn());
		qf.setExtraPluginId(ID);
		String resp = respToParkFeeCacheBeanQueryParkingFee(lot.getSn(), exit, totalCalcFee);
		Long uniqueId = submitUpdateOriginalInfoTask(lot.getSn(), exit.getCarPlate(), exit.getFee(), resp);
		log.debug("uniqueId = {}", uniqueId);
		qf.setUniqueId(uniqueId != null ? String.valueOf(uniqueId) : "");
		qf.setIsSuccess(true);
		return qf;
	}

	/**
	 * 因为请求订单的方式不同, 所以数据结果不同, 这区将预支付和 扫码支付通道数据解析分开
	 * 
	 * @param lotSn
	 * @param exit
	 *            redis中取出的车辆停车信息
	 * @param totalCalcFee
	 *            订单总金额
	 * @return
	 */
	public String respToParkFeeCacheBeanQueryParkingFee(String lotSn, ExitingCar exit, Float totalCalcFee) {
		ParkingLot lot = lotService.findBySn(lotSn);
		String carPlate = exit.getCarPlate();
		Date inTime = DateUtils.parse(exit.getInTime());
		// 车厂生成车辆入场编号
		String orderId = exit.getLotRecordId();
		/** 蓝卡返回的信息无车道信息 所以填null */
		ParkingIn in = inService.enter(lot, carPlate, inTime, null, lot.getFreeMinutes(), orderId, null);
		// 车厂订单编号, 车辆入场时由车厂生成
		String lotOrderSn = exit.getLotOrderNo();
		Date endTime = DateUtils.parse(exit.getOutTime());
		ParkFeeCacheBean bean = new ParkFeeCacheBean();
		bean.setCarPlate(carPlate);
		bean.setEndTime(endTime);
		bean.setLotOrderNo(lotOrderSn);
		bean.setParkPluginId(ID);
		bean.setTotalFee(totalCalcFee);
		bean.setDiscountFee(exit.getDiscountFee());
		bean.setUniqueId(in.getUniqueId());
		return JSONObject.toJSONString(bean);
	}

	// 通知车厂支付成功 如果有当前车牌等待出场会抬杆抬杆
	@Override
	public boolean notifyParkingFeeOrderSuccess(NotifyParkingLotMsg msg) {
		String lotSn = msg.getLocalLotSn();
		ParkingLot lot = lotService.findBySn(lotSn);
		// 查询本比订单号信息
		Order lotOrder = orderService.findBySn(msg.getLocalOrderSn());
		// 如果是预支付 修改入场记录的上次缴费时间
		if (Order.Method.prepay.equals(lotOrder.getMethod())) {
			ParkingIn parkIn = inService.findByCarPlate(lot.getId(), msg.getCarPlate());
			parkIn.setLastChargeTime(lotOrder.getPaytime());
			inService.update(parkIn);
		}
		// 如果是预支付 修改入场记录的上次缴费时间
		BluecardNotifyParkingFeeOrderSuccess notify = new BluecardNotifyParkingFeeOrderSuccess();
		// 车厂的车厂编号
		notify.setParkNumber(msg.getOutLotSn());
		// 车厂入场编号
		notify.setOrderId(msg.getOutParkRecordId());
		notify.setPlate(msg.getCarPlate());
		// 应付金额 实付金额
		String money = String.valueOf(lotOrder.getMoney().floatValue());
		notify.setPayCharge(money);
		notify.setRealCharge(money);
		// 支付时间
		notify.setPayTime(DateUtils.format(lotOrder.getPaytime()));
		// 支付方式 目前线上有支付宝 微信 , 线下有现金 这里只算线上
		notify.setPayType(Platform.weixin.equals(lotOrder.getPlatform()) ? "微信" : "支付宝");
		notify.setPayChannel("扫码付");
		notify.setGetTiem(DateUtils.format(lotOrder.getEndtime()));
		notify.setTransactionID(lotOrder.getSn());
		// 车厂发送的流水号
		notify.setOutTradeNo(lotOrder.getLotOrderNo());
		// 请求信息组装完毕
		String sign = Md5Utils.md5(lot.getApiKey() + notify.getParkNumber());
		// 发送支付成功请求
		String res = httpPost(lot, "/bcopenapi/out/sendPayRes", JSONObject.toJSONString(notify), sign);
		if (res == null) {
			throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
		}
		JSONObject httpJson = JSONObject.parseObject(res);
		String status = httpJson.getString("status");
		return "success".equals(status);
	}

	public String httpPost(ParkingLot lot, String uri, String dataJson, String sign) {
		HEADER.put("sign", sign);
		return postJson(lot.getSn(), lot.getApiUrl() + uri, dataJson, HEADER, lot.getIsTcp());
	}

	@Override
	public boolean notifyMonthCardChargeOrderSuccess(String order, String lotSn, String carPlate) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public McardQueryResultWrap monthCardQuery(String lotSn, MemberCarPlate carPlate) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public McardQueryResultWrap monthCardChargePreview(String lotSn, String carPlate, Integer month) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ParkingLotInfoQueryResultWrap parkingLotInfoQuery(String lotSn) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public McardQueryChargeOptionsResultWrap monthCardQueryChargeOptions(String lotSn) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public McardChargeOrderCreateResultWrap monthCardCreateOrder(MemberCarPlate memberCarPlate, CreateMcardChargeOrderDTO dto, Platform platform) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public McardCancelResultWrap monthCardCancel(String lotSn, String carPlate) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String execute(String api, String lotSn, Map map) {
		// TODO Auto-generated method stub
		return null;
	}

	public static void returnResponse(HttpServletResponse response, String result) {
		response.setHeader("content-type", "application/json;charset=UTF-8");
		try {
			PrintWriter pw = response.getWriter();
			pw.write(result);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 入场通知 入库数据 入场记录发送的很全 人员信息 停车位 停车区域信息等
	 */
	@Override
	public void afterInNoticeHanler(HttpServletRequest request, HttpServletResponse response, ParkingLot parkingLot) {
		String sign = request.getHeader("sign");
		String json;
		try {
			json = IOUtils.toString(request.getInputStream(), "utf-8");
		} catch (IOException e) {
			returnResponse(response, BluecardResult.failJson("read request body error! "));
			return;
		}
		JSONObject jsonObj = JSON.parseObject(json);
		String parkNumber = jsonObj.getString("parkNumber");
		log.debug("parkNumber+key is = {} ", parkingLot.getApiKey() + parkNumber);
		String localSign = Md5Utils.md5(parkingLot.getApiKey() + parkNumber);
		// 验证签名
		log.debug("bluecard localsign is {}, ---- sign = {}", localSign, sign);
		JSONArray datas = jsonObj.getJSONArray("datas");
		// 返回结果
		String result = null;
		// 验证签名
		if (!sign.equals(localSign)) {
			result = BluecardResult.failJson("签名错误!");
		} else if (datas != null && datas.size() > 0) {
			String carPlate = null;
			Date inTime = null;
			String name = null;
			ParkChannel parkChannel = null;
			for (Object object : datas) {
				JSONObject data = (JSONObject) object;
				// 车牌
				carPlate = data.getString("plate");
				// 如果是无牌 暂时不入库
				if (carPlate == null || "".equals(carPlate))
					continue;
				inTime = DateUtils.parse(data.getString("inTime"));
				name = data.getString("inChannel");
				// 根据请求发送来的 车道名称获取 本系统车道id
				parkChannel = channelService.findByParkingLotAndTypeAndName(parkingLot, ParkChannel.Type.entrance, name);
				// parkingIn 存入的车厂id 就是 id 出入的车道入口id 就是id
				inService.enter(parkingLot, carPlate, inTime, parkChannel != null ? parkChannel.getId() : null, parkingLot.getFreeMinutes(), data.getString("orderId"), null);
			}
			Map<String, String> datamap = new HashMap<String, String>();
			datamap.put("timestamp", String.valueOf(System.currentTimeMillis()));
			result = BluecardResult.successJson(datamap);
		} else {
			result = BluecardResult.failJson("解析数据失败!");
		}
		// 给车厂返回结果 , 如果返回 fail 会每十分钟发送一次本批数据
		returnResponse(response, result);
	}

	/**
	 * 出库通知 入库
	 */
	@Override
	public void afterOutNoticeHanler(HttpServletRequest request, HttpServletResponse response, ParkingLot parkingLot) {
		String sign = request.getHeader("sign");
		String json;
		try {
			json = IOUtils.toString(request.getInputStream(), "utf-8");
		} catch (IOException e) {
			returnResponse(response, BluecardResult.failJson("read request body error! "));
			return;
		}
		log.debug("json = {}", json);
		JSONObject jsonObj = JSON.parseObject(json);
		String parkNumber = jsonObj.getString("parkNumber");
		String localSign = Md5Utils.md5(parkingLot.getApiKey() + parkNumber);
		JSONArray datas = JSONArray.parseArray(jsonObj.getString("datas"));
		String result = null;
		if (!sign.equals(localSign)) {
			result = BluecardResult.failJson("签名错误!");
		} else if (datas != null && datas.size() > 0) {
			Long lotId = parkingLot.getId();
			for (Object object : datas) {
				JSONObject data = (JSONObject) object;
				JSONObject carInfo = data.getJSONObject("carInfo");
				// 车牌
				String carPlate = carInfo.getString("plate");
				if (carPlate == null || "".equals(carPlate))
					continue;
				String orderId = data.getString("orderId");
				int size = parkingInOutServiceImpl.countByParkingLotIdAndLotRecordId(lotId, orderId);
				// 如果存在已经出场的相同记录, 不进行操作
				if (size != 0) {
					ParkingIn repeatIn = inService.findByParkingLotIdAndLotRecordId(lotId, orderId);
					if (repeatIn != null) {
						inService.delete(repeatIn.getId());
					}
					continue;
				}
				JSONObject passInfo = data.getJSONObject("passInfo");
				// 根据车牌查询入场信息
				ParkingIn in = inService.findByCarPlate(parkingLot.getId(), carPlate);
				// 如果没有入场记录, 根据出场记录模拟入场记录
				// 如果没有入场记录, 那么必然无订单, 这种订单走现金, 标注再remark中
				boolean inexistence = false;
				if (in == null) {
					inexistence = true;
					String inName = passInfo.getString("inChannel");
					ParkChannel parkInChannel = channelService.findByParkingLotAndTypeAndName(parkingLot, ParkChannel.Type.entrance, inName);
					Date inTime = DateUtils.parse(passInfo.getString("inTime"));
					in = inService.enter(parkingLot, carPlate, inTime, parkInChannel != null ? parkInChannel.getId() : null, parkingLot.getFreeMinutes(), orderId, null);
				} else {
					// 如果存在入场纪录下 无任何订单 那么将生成现金订单
					int orderCount = orderService.countByUniqueId(in.getUniqueId());
					if (orderCount == 0)
						inexistence = true;
				}

				// 通道名称
				String name = passInfo.getString("outChannel");
				// 根据车厂信息, 通道类型, 通道名称 查询出本系统车道id
				Date outTime = DateUtils.parse(passInfo.getString("outTime"));
				ParkChannel parkChannel = channelService.findByParkingLotAndTypeAndName(parkingLot, ParkChannel.Type.exit, name);
				ParkingInOut out = parkingInOutServiceImpl.out(in, outTime, parkChannel == null ? null : parkChannel.getId(), in.getLotRecordId());
				JSONArray chargeList = data.getJSONArray("chargeList");
				if (chargeList != null && chargeList.size() > 0) {
					for (Object obj : chargeList) {
						JSONObject charge = (JSONObject) obj;
						// 没有订单, 强行生成现金订单
						String payKind = inexistence ? "现金" : charge.getString("payKind");
						if ("微信".equals(payKind) || "支付宝".equals(payKind))
							continue;
						// 车厂支付订单号
						BigDecimal payCharge = charge.getBigDecimal("payCharge");
						String payNo = charge.getString("payNo");
						Date getTime = DateUtils.parse(charge.getString("getTime"));

						Order order = new Order();
						// 人工缴费
						order.setMethod(Order.Method.manual);
						order.setMoney(payCharge);
						order.setServiceCharge(new BigDecimal(0));
						order.setRefundMoney(new BigDecimal(0));
						order.setSn(sequenceUtils.nextIdStr());
						order.setLotOrderNo(payNo);
						order.setMchid(parkingLot.getMchid());
						order.setPayStatus(PayStatus.success);
						order.setCarPlate(carPlate);
						// 支付类别: 这里目前都是现金
						order.setPlatform(Platform.cash);
						order.setPayMode(PayMode.jssdk);
						order.setUniqueId(in.getUniqueId());
						order.setEntertime(in.getInTime());
						order.setStarttime(in.getInTime());
						order.setEndtime(out.getOutTime());
						order.setRemark(inexistence ? "未找到入场记录或者无订单" : "");
						order.setParkingLotName(parkingLot.getName());
						order.setParkingLotSn(parkingLot.getSn());
						order.setIsRiseSuccess(true);
						order.setPaytime(getTime);
						order.setPluginId(ID);
						order.setParkingLot(parkingLot);
						order.setExitId(parkChannel.getId());

						// 优惠金额
						JSONObject chargeStatistics = JSONObject.parseObject(data.getString("chargeStatistics"));
						BigDecimal profitChargeTotal = chargeStatistics.getBigDecimal("profitChargeTotal");
						order.setTotalDiscount(profitChargeTotal);

						orderService.save(order);
					}
				}
			}
			Map<String, String> map = new HashMap<String, String>();
			map.put("timestamp", String.valueOf(System.currentTimeMillis()));
			result = BluecardResult.successJson(map);
		} else {
			result = BluecardResult.failJson("解析数据失败!");
		}
		// 给车厂返回结果 , 如果返回 fail 3次 会每5分钟发送一次本批数据
		returnResponse(response, result);
	}
	
	@Override
	public void beforeOutNoticeHandler(HttpServletRequest request, HttpServletResponse response, ParkingLot parkingLot) {
		// TODO Auto-generated method stub
		
	}

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		map.put("a", null);
		map.put("b", "b");
		map.put("c", null);
		System.out.println(JSONObject.toJSONString(map));

		BluecardCharge bCharge = new BluecardCharge();
		BluecardResultData bdata = new BluecardResultData(new ArrayList<BluecardCharge>());
		bdata.getChargeList().add(bCharge);
		bdata.setTimeStamp(String.valueOf(System.currentTimeMillis()));
		BluecardResult b = BluecardResult.success(bdata);
		System.out.println(JSONObject.toJSONString(b));
		System.out.println(JSONObject.toJSONString(b, SerializerFeature.WriteMapNullValue));
		System.out.println(JSONObject.toJSONString(b, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty));
	}

}
